﻿using BarManagement.DomainService.Base;
using System;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;

namespace BarManagement.Infrastructure.DataAccess.Base
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly IDataContext _context;
        private bool _disposed;
        private Hashtable _repositories;

        public UnitOfWork(IDataContext context)
        {
            _context = context;
        }

        public IRepository<TEntity> Repository<TEntity>() where TEntity : class
        {
            if (_repositories == null) _repositories = new Hashtable();
            var type = typeof(TEntity).Name;

            if (_repositories.ContainsKey(type)) return (IRepository<TEntity>)_repositories[type];
            var repositoryType = typeof(RepositoryBase<TEntity>);
            _repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), _context));

            return (IRepository<TEntity>)_repositories[type];
        }

        public void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
            {
                _context.Dispose();
                foreach (IDisposable repository in _repositories.Values) repository.Dispose();
            }
            _disposed = true;
        }

        public void BeginTransaction()
        {
            _context.BeginTransaction();
        }

        public void Rollback()
        {
            _context.Rollback();
        }

        public Task<int> SaveChangesAsync()
        {
            return _context.SaveChangesAsync();
        }

        public Task<int> SaveChangesAsync(CancellationToken cancellationToken)
        {
            return _context.SaveChangesAsync(cancellationToken);
        }

        public Task<int> CommitAsync()
        {
            return _context.CommitAsync();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}
